import os
import secrets
from enum import Enum
from pathlib import Path
from typing import Optional

from pydantic import AnyUrl, Field
from pydantic_settings import BaseSettings, SettingsConfigDict


class DatabaseType(str, Enum):
    SQLITE = "sqlite"
    MYSQL = "mysql"
    POSTGRESQL = "postgresql"
    SQLSERVER = "sqlserver"


class CacheType(str, Enum):
    REDIS = "redis"
    MEMORY = "memory"

class AuthType(str, Enum):
    ROLE = "role"
    MENU = "menu"
    API = "api"
    NONE = "none"


class ModeEnum(str, Enum):
    """
    development 开发环境\n
    production 生产环境\n
    testing 测试环境
    """
    development = "development"
    production = "production"
    testing = "testing"


class Settings(BaseSettings):
    MODE: ModeEnum = Field(default=ModeEnum.development, description="开发模式")

    BASE_DIR: Path  = Field(default=os.path.dirname(os.path.dirname(os.path.abspath(__file__))),description="项目根目录")

    PROJECT_NAME: str = Field(default="fastapi", description="项目名称")
    TITLE: str = Field(default="My API", description="标题")
    API_VERSION: str = Field(default="v1", description="api版本")
    API_V1_STR: str = Field(default=f"/api/{API_VERSION}", description="api版本字符串")

    # 数据库配置
    DB_TYPE: DatabaseType = Field(default=DatabaseType.SQLITE, description="数据库类型")
    DB_NAME: str = Field(default="sql_app.db", description="数据库名称")
    DB_DRIVER: str = Field(default="aiosqlite", description="驱动程序")
    DB_URL: AnyUrl = Field(
        default="sqlite+aiosqlite:///./sql_app.db", description="数据库连接地址"
    )

    @property
    def db_url(self) -> str:
        return f"{self.DB_TYPE.value}+{self.DB_DRIVER}:///./{self.DB_NAME}"

    """
        设置数据库连接池中保持的空闲连接数量（默认通常为 5）
        连接池会预先创建 pool_size 个连接，供后续请求快速使用
        如果所有连接都在使用中，新的请求需要等待（直到超时或连接释放）
        高并发应用可以适当增大 pool_size，但不要超过数据库的最大连接数限制
    """
    DB_POOL_SIZE: int = Field(default=5, description="空闲连接数")
    """
        允许连接池临时超出 pool_size 的连接数量（默认通常为 10）
        当所有连接都在使用时，可以临时创建最多 max_overflow 个额外连接
        用完后，这些额外连接会被关闭，连接池恢复到 pool_size 的大小
        总连接数 = pool_size + max_overflow
        如果数据库有最大连接数限制（如 MySQL 的 max_connections），需确保不会超出
    """
    DB_MAX_OVERFLOW: int = Field(default=10, description="临时连接数")
    """
    在从连接池获取连接时，先执行一个简单的测试查询（如 SELECT 1）来检查连接是否仍然有效。如果连接已失效，则会自动重新建立一个新的连接返回给应用
    为什么需要 pool_pre_ping
    数据库连接可能会因为以下原因失效：
        数据库服务器重启（维护、崩溃等）
        网络问题（连接超时、防火墙中断等）
        数据库主动断开空闲连接（如 MySQL 的 wait_timeout 设置）
        连接池中的连接长时间未被使用（超过数据库或防火墙的闲置超时）
    如果没有 pool_pre_ping，当应用尝试使用一个已失效的连接时，会直接抛出类似 OperationalError 或 InterfaceError 的错误，导致请求失败
    """
    DB_POOL_PRE_PING: bool = Field(default=True, description="临时连接数")
    """
        控制是否打印执行的 SQL 语句和连接池操作（默认 False）
        开发时开启，生产环境关闭，避免日志过多
    """
    DB_ECHO: bool = Field(default=True, description="是否打印 SQL 日志")

    """权限相关"""
    AUTH_TYPE:AuthType = Field(default=AuthType.MENU, description="使用那种权限进行鉴权")
    AUTH_WHITE_LIST: list[str] = Field(default=[], description="权限白名单")
    SECRET_KEY: str = Field(default=secrets.token_urlsafe(32), description="秘密密钥")
    ENCRYPT_KEY: str = Field(
        default=secrets.token_urlsafe(32), description="加密键密钥"
    )
    ALGORITHM: str = Field(default="HS256", description="加密算法")
    ACCESS_TOKEN_EXPIRE_MINUTES: int = Field(
        default=60 * 60 * 1, description="token过期时间，默认一小时，单位秒"
    )
    REFRESH_TOKEN_EXPIRE_MINUTES: int = Field(
        default=60 * 60 * 24 * 7, description="刷新token过期时间，默认一星期，单位秒"
    )
    TOKEN_VERSION_CACHE_PREFIX: str = Field(
        default="TOKEN_VERSION_CACHE_PREFIX", description="token版本缓存键前缀"
    )
    REFRESH_TOKEN_CACHE_PREFIX: str = Field(
        default="REFRESH_TOKEN_CACHE_PREFIX", description="刷新token缓存键前缀"
    )

    DEFAULT_PASSWORD: str = Field(default="swk123", description="用户默认密码")

    # 缓存配置
    CACHE_TYPE: CacheType = Field(default=CacheType.MEMORY, description="缓存类型")
    REDIS_HOST: str = Field(default="localhost", description="Redis主机")
    REDIS_PORT: int = Field(default=6379, description="Redis端口")
    REDIS_DB: int = Field(default=0, description="Redis数据库")
    REDIS_PASSWORD: Optional[str] = Field(default=None, description="Redis密码")
    REDIS_PREFIX: str = Field(default="fastapi:", description="缓存键前缀")


    WEB_ROOT:str = Field(default=os.getenv("WEB_ROOT", "static"))
    DEFAULT_UPLOAD_FILE_DIR: str = Field(default="upload", description="文件上传保存文件夹")
    MAX_FILE_SIZE:int = Field(default=1024 * 1024 * 100)

    model_config = SettingsConfigDict(
        env_file=".env",
        env_file_encoding="utf-8",
        case_sensitive=True,
        extra="ignore",  # 忽略额外字段
    )


settings = Settings()

















